Skip to content

feat: project-defined roles with node-scoped grants - #1303

Merged
kvlonge merged 10 commits into
feat/orchestration-backendfrom
feat/project-roles
Nov 5, 2026
Merged

kvlonge merged 10 commits into
feat/orchestration-backendfrom
feat/project-roles

Conversation

@kvlonge

@kvlonge kvlonge commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Why

Projects need reviewed custom roles whose grants follow the nodes they select, checked on every node an operation touches. Stacked on #1282; draft.

Changes

  • roles.toml at the project root: [roles.X] with [[roles.X.grants]] of nodes selectors and permissions. sqb location publish resolves each selector with the job selection grammar into the snapshot roles document. A grant matching nothing warns and grants nothing.
  • The definition digest covers only selectors and permissions, so new matching nodes apply on publish without approval.
  • Effective grants are the approved (selector, permission) pairs that the new definition still contains, resolved against the new snapshot. Removed pairs stop at once; added pairs wait for approval. Coverage changes enter the snapshot change feed as role:<key>.
  • Authorization takes the union across a person's custom roles. Runs and trigger overrides need the permission on every node the job writes; location listings need view on every node; view.sql is per node. A denial lists up to 20 missing nodes.
  • Docs: a project-roles section in cli/server.

Verification

  • Native role tests, 16/16 on SQLite and PostgreSQL: trigger and listing scope; selector growth without approval; a rewritten selector waits; removal and rewrite in one publish; zero nodes or a removed role grants nothing; all-or-nothing ad-hoc denial; union across roles; roles.toml compilation.
  • Deliberate breaks fail: keeping removed pairs, treating every change as narrowing, counting only the first role, and granting with zero resolved nodes.
  • Full orchestration native suite: 106/106.
  • Installed test_project_roles.py: publish warning, per-node SQL denial, growth, and a rewrite waiting for approval.
  • DuckShop: project_roles.toml; custom_role_approval.json updated.
  • Installed publication suite: 142 passed, 2 skipped at dd19d9d; its 13 person and role tests pass at the tip.
  • make check-ci and the hygiene scan pass.

Work in progress, not yet ready for review.

roles.toml at the project root defines project roles. Each grant's node
selectors resolve per snapshot when the location publishes. Effective
grants are the approved (selector, permission) pairs that the new
definition still contains: removals apply at once, and additions wait
for an administrator's approval. Runs need the permission on every node
they write, view.sql is checked per node, and authorization takes the
union across a person's roles.

Validated so far: the native role tests (13, on SQLite and PostgreSQL),
the full orchestration native suite (104), the installed
test_project_roles.py, Fensu and the hygiene scan. Not yet run:
make check-ci. The full publication suite has failures that are still
being attributed.
make check-ci now passes on this branch: clippy with -D warnings, ruff
and Fensu.
When a publication changes a custom role's effective grants, either by
removing pairs or by changing selector coverage, the change is appended
to that snapshot's change feed as role:<key>, as CHI-907 section 13
requires.

Validated: the native role tests (13 on SQLite and PostgreSQL), the full
orchestration native suite (104) and make check-ci.
trigger.toggle and sensor.reset_cursor are now authorized on every node
the trigger's current job or group writes, all or nothing, as job.run
is. A role covering only some of those nodes can no longer pause or
reset the trigger.

The catalog, statistics and run listings span the whole location, so
they now need view coverage of every node in the current publication.
Partial coverage is denied and names the missing nodes; results are
never filtered.

Validated: the native role tests (15, on SQLite and PostgreSQL),
deliberate breaks of both fixes, the full orchestration native suite
(106), 13 installed publication tests and make check-ci.
A member keeps an assignment to a role that a later snapshot no longer
defines. The assignment must grant nothing, on nodes or location-wide,
and the removal must appear in the change feed. Covered on SQLite and
PostgreSQL.
Project roles now take effect on publish; the activation and approval
workflow, its tables and its docs are gone. The merge also brings the
group concurrency fix and the follow-up simplification batch.
# Conflicts:
#	crates/sqlbuild-orchestration/src/authorization/main/authorize_person.rs
@kvlonge
kvlonge merged commit 0dd7740 into feat/orchestration-backend Nov 5, 2026
26 of 47 checks passed
@kvlonge
kvlonge deleted the feat/project-roles branch November 5, 2026 18:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant